﻿// Copyright 2007, 2008 - Ariel Yaroshevich (a.k.a blackrussian) (hamlet@inter.net.il)
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpMap.Presentation.Views;
using SharpMap.Presentation.Presenters;
using SharpMap.Rendering;
using SharpMap.Rendering.Rendering2D;
using SharpMap.Tools;
using SharpMap.Layers;
using SharpMap.Data;
using System.Data;
using SharpMap.Geometries;
using System.Diagnostics;
using SharpMap.Expressions;
using GeoPoint = SharpMap.Geometries.Point;

using System.Windows.Input;



namespace SharpMap.Presentation.Wpf
{
    public static class WpfMapTools
    {
        public static readonly MapTool<IMapView2D, Point2D> Pan;
        public static readonly MapTool<IMapView2D, Point2D> ZoomMouse;
        public static readonly MapTool<IMapView2D, Point2D> MoveObject;
        public static readonly MapTool<IMapView2D, Point2D> MeasureDistance;
        public static readonly MapTool<IMapView2D, Point2D> SelectMove;
        public static readonly MapTool<IMapView2D, Point2D> SelectRectangle;
        public static readonly MapTool<IMapView2D, Point2D> ZoomRectangle;

        private static readonly IEnumerable<uint> EmptyOids = new uint[0];
        static WpfMapTools()
        {
            Pan = new MapTool<IMapView2D, Point2D>("Pan", PanQuery, PanBegin, PanExtend, PanEnd);
            ZoomMouse = new MapTool<IMapView2D, Point2D>("ZoomMouse", ZoomMouseQuery, ZoomMouseBegin, ZoomMouseExtend, ZoomMouseEnd);
            MoveObject = new MapTool<IMapView2D, Point2D>("Move Object", MoveQuery, MoveBegin, MoveExtend, MoveEnd);
            MeasureDistance = new MapTool<IMapView2D, Point2D>("Measure Distance", MeasureQuery, MeasureBegin, MeasureExtend, MeasureEnd);
            SelectRectangle = new MapTool<IMapView2D, Point2D>("Select Rectangle", SelectRectangleQuery, SelectRectangleBegin, SelectRectangleExtend, SelectRectangleEnd);
            SelectMove = new MapTool<IMapView2D, Point2D>("Select", SelectMoveQuery, SelectMoveBegin, SelectMoveExtend, SelectMoveEnd);
            ZoomRectangle = new MapTool<IMapView2D, Point2D>("Zoom Rectangle", ZoomRectangleQuery, ZoomRectangleBegin, ZoomRectangleExtend, ZoomRectangleEnd);
        }

        #region ZoomMouse
        private static void ZoomMouseQuery(ActionContext<IMapView2D, Point2D> context)
        {
        }
        private static void ZoomMouseBegin(ActionContext<IMapView2D, Point2D> context)
        {
        }
        private static void ZoomMouseExtend(ActionContext<IMapView2D, Point2D> context)
        {
            if(context.CurrentPoint.Y - context.PreviousPoint.Y > 0)
            {
                 zoomByFactor(context, 0.8) ;
            }
            else
            {
                 zoomByFactor(context, 1.2);
            }  
        }
        private static void ZoomMouseEnd(ActionContext<IMapView2D, Point2D> context)
        {  
        }
        #endregion // ZoomOut

        //-----------------------------------------------------
        //
        //  Pan
        //
        //-----------------------------------------------------

        #region Pan
        private static void PanQuery(ActionContext<IMapView2D, Point2D> context)
        {
    
        }
        private static void PanBegin(ActionContext<IMapView2D, Point2D> context)
        {
        }
     
        private static void PanExtend(ActionContext<IMapView2D, Point2D> context)
        {
            Point2D diffV = context.PreviousPoint - context.CurrentPoint;
            System.Windows.UIElement uie = context.MapView as System.Windows.UIElement;
            if (uie != null)
            {
                MapCommands.Offset.Execute(diffV, uie);
            }
        }
        private static void PanEnd(ActionContext<IMapView2D, Point2D> context)
        {
        }

        #endregion // Pan
    

        #region SelectMove
        private static void SelectMoveQuery(ActionContext<IMapView2D, Point2D> context)
        {
    
        }
        private static void SelectMoveBegin(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;
            view.Selection.AnchorPoint = context.CurrentPoint;

            if (view.GeoCenter == Point.Empty)
            {
                throw new InvalidOperationException("No visible region is set for this view.");
            }

            MapView mvc = context.MapView as MapView;
            if (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.LeftCtrl) ||
                 System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.RightCtrl))
            {
                if (mvc != null)
                {
                    mvc.IsMultiselectEnabled = true;
                }
            }

            MapView viewControl = view as MapView;
            MapViewModel presenter = viewControl.ViewModel as MapViewModel;

            int selectedFeaturesTotalCount = 0;
            foreach (ILayer ilayer in context.Map.SelectedLayers)
            {

                SharpMap.Styles.VectorStyle vStyle = ilayer.Style as SharpMap.Styles.VectorStyle;
                if (vStyle == null || !vStyle.AreFeaturesSelectable)
                {
                    continue;
                }

                IFeatureLayer featureLayer = ilayer as IFeatureLayer;
                IFeatureLayerProvider provider = featureLayer.DataSource;

                List<uint> rows = new List<uint>();
                foreach (DataRowView drv in featureLayer.SelectedFeatures)
                {
                    FeatureDataRow<uint> fdr = drv.Row as FeatureDataRow<uint>;
                    if(fdr != null)
                    {

                        BoundingBox bb = featureLayer.Extents;
                        if(bb.Contains(viewControl.ToWorld(  context.CurrentPoint)))
                        {
                            rows.Add((uint)fdr.GetOid());
                        }
                    }
                }
                               
                foreach (uint oid in rows)
                {
                    if (!mvc.IsMultiselectEnabled && featureLayer.SelectedFeatures.Find(oid) != -1)
                    {
                        return;
                    }
                }

                if (mvc.IsMultiselectEnabled)
                {
                    List<uint> newSelectedOids = new List<uint>(rows);
                    if (featureLayer.SelectedFeatures.OidFilter != null)
                    {
                        foreach (uint oid in featureLayer.SelectedFeatures.OidFilter)
                        {
                            if (!newSelectedOids.Contains(oid))
                                newSelectedOids.Add(oid);
                            else
                                newSelectedOids.Remove(oid);
                        }
                    }
                    featureLayer.SelectedFeatures.ViewDefinition =
                          new FeatureSpatialExpression(viewControl.ViewEnvelope.ToGeometry(), SpatialExpressionType.Contains, newSelectedOids);
                }
                else
                {
                    featureLayer.SelectedFeatures.ViewDefinition =
                          new FeatureSpatialExpression(viewControl.ViewEnvelope.ToGeometry(), SpatialExpressionType.Contains, rows);
                }


                selectedFeaturesTotalCount += featureLayer.SelectedFeatures.Count;
            }

            // didnt select anything, activate the select rectangle tool
            if (selectedFeaturesTotalCount == 0)
            {
                viewControl.Map.ActiveTool = WpfMapTools.SelectRectangle;
                view.Selection.Clear();
                WpfMapTools.SelectRectangle.BeginAction(context);
            }
        }
    
        private static void SelectMoveExtend(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;

            Point2D previousPoint = context.PreviousPoint;

            Point2D currentPoint = context.CurrentPoint;
            Point2D difference = previousPoint - currentPoint;

            Matrix2D trans = new Matrix2D();
            trans.OffsetX = difference.X * view.PixelWorldWidth;
            trans.OffsetY = difference.Y * view.PixelWorldHeight;
            foreach (ILayer l in context.Map.SelectedLayers)
            {
                SharpMap.Styles.VectorStyle vStyle = l.Style as SharpMap.Styles.VectorStyle;
                if (vStyle == null || !vStyle.AreFeaturesSelectable)
                {
                    continue;
                }

                GeometryLayer layer = l as GeometryLayer;
                if (layer == null)
                {
                    continue;
                }
                Type itfType = layer.DataSource.GetType().GetInterface(typeof(IWritableFeatureLayerProvider<>).Name);

                if (itfType == null)
                {
                    continue;
                }



                IWritableFeatureLayerProvider<Guid> layerProviderGuid = layer.DataSource as IWritableFeatureLayerProvider<Guid>;
                IWritableFeatureLayerProvider<uint> layerProviderUint = layer.DataSource as IWritableFeatureLayerProvider<uint>;
                if (layerProviderGuid == null && layerProviderUint == null)
                {
                    continue;
                }

                FeatureDataView selectedFeatureView = layer.SelectedFeatures;

                foreach (object o in selectedFeatureView)
                {
                    DataRowView dataRawView = o as DataRowView;
                    if (dataRawView != null)
                    {

                        FeatureDataRow<uint> row = dataRawView.Row as FeatureDataRow<uint>;

                        IEnumerable<SharpMap.Geometries.Point> vertices = row.Geometry.GetVertices();

                        foreach (SharpMap.Geometries.Point vertex in vertices)
                        {
                            vertex.X -= trans.OffsetX;
                            vertex.Y += trans.OffsetY;
                        }
                    }
                }
                selectedFeatureView.Table.AcceptChanges();
            }
        }
        private static void SelectMoveEnd(ActionContext<IMapView2D, Point2D> context)
        {
        }

        #endregion // Select
    
        #region Move
        private static void MoveQuery(ActionContext<IMapView2D, Point2D> context)
        {
            //Point2D point = context.CurrentPoint;
            //context.
            //SharpMap.Geometries.Point worldPoint = context.MapView.ToWorld(point);
            //context.MapView.IdentifyLocation(worldPoint);

        }
        private static void MoveBegin(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;
            view.Selection.AnchorPoint = context.CurrentPoint;
        }
        private static void MoveExtend(ActionContext<IMapView2D, Point2D> context) 
        {
            IMapView2D view = context.MapView;
            Point2D previousPoint = context.PreviousPoint;

            Point2D currentPoint = context.CurrentPoint;
            Point2D difference = previousPoint - currentPoint;

            Matrix2D trans = new Matrix2D();
            trans.OffsetX = difference.X * view.PixelWorldWidth;;
            trans.OffsetY = difference.Y * view.PixelWorldHeight;
            foreach (ILayer l in context.Map.SelectedLayers)
            {
                GeometryLayer layer = l as GeometryLayer;
                if (layer == null)
                {
                    continue;
                }
                Type itfType = layer.DataSource.GetType().GetInterface(typeof(IWritableFeatureLayerProvider<>).Name);
                
                if(itfType == null)
                {
                    continue;
                }
                
       
                IWritableFeatureLayerProvider<Guid> layerProviderGuid = layer.DataSource as IWritableFeatureLayerProvider<Guid>;
                IWritableFeatureLayerProvider<uint> layerProviderUint = layer.DataSource as IWritableFeatureLayerProvider<uint>;
                if (layerProviderGuid == null && layerProviderUint == null)
                {
                    continue;
                }
                
                FeatureDataView selectedFeatureView = layer.SelectedFeatures;
                
                foreach (object o in selectedFeatureView)
                {
                    DataRowView dataRawView = o as DataRowView ;
                    if(dataRawView != null)
                    {
                        FeatureDataRow<uint> row =  dataRawView.Row as FeatureDataRow<uint> ;
                        IEnumerable<SharpMap.Geometries.Point> vertices = row.Geometry.GetVertices();

                        foreach(SharpMap.Geometries.Point vertex in vertices)
                        {
                            //trans.TransformVectors()
                            vertex.X -= trans.OffsetX;
                            vertex.Y += trans.OffsetY; 
                            
                        }
 
                         
                    }
                }
                selectedFeatureView.Table.AcceptChanges();
            }
        }
        private static void MoveEnd(ActionContext<IMapView2D, Point2D> context) { }
        #endregion // Move

     
        

        #region Measure Distance
        private static void MeasureQuery(ActionContext<IMapView2D, Point2D> context)
        {
        }
     
        private static void MeasureBegin(ActionContext<IMapView2D, Point2D> context)
        {
            MapView view = context.MapView as MapView;
            Debug.Assert(view != null);
            MapViewModel presenter = view.ViewModel;
            Debug.Assert(presenter != null);
            view.Selection.AnchorPoint = context.CurrentPoint;
        }

        private static void MeasureExtend(ActionContext<IMapView2D, Point2D> context)
        {
            MapView view = context.MapView as MapView;
            Debug.Assert(view != null);
            MapViewModel presenter = view.ViewModel as MapViewModel;
            Debug.Assert(presenter != null);
            
            Path2D path = new Path2D();
            path.AddPoint(view.Selection.AnchorPoint);
            path.AddPoint(context.CurrentPoint);
            path.TransformPoints(view.ToWorldTransform);

            Point2D p1 = path.Points[0];
            Point2D p2 = path.Points[1];

            // used only for distance3
            SharpMap.Geometries.Point sp1 = view.ToWorld(view.Selection.AnchorPoint);
            SharpMap.Geometries.Point sp2 = view.ToWorld(context.CurrentPoint);
        
            double distance1 = MeasureDistance1(p1,p2);   // old function, good only for the equator
            double distance2 = MeasureDistance2(p1, p2);   // new function, uses Gavaghan.Geodesy.dll
            double distance3 = sp1.Distance(sp2)*111.2;    // simple way, doesnt work properly
            
            
            Debug.WriteLine(String.Format("old distance = {0:F2}", distance1));
            Debug.WriteLine(String.Format("new distance = {0:F2}", distance2));
            Debug.WriteLine(String.Format("simple distance = {0:F2}", distance3));
            Debug.WriteLine("*************************************");

            //presenter.DrawPath(path);
            

        }

        private static void MeasureEnd(ActionContext<IMapView2D, Point2D> context)
        {
        }
        #endregion // Measure Distance

        public static System.Windows.Media.Drawing RenderText(String text, SharpMap.Styles.StyleFont font, Rectangle2D layoutRectangle, Path2D flowPath, SharpMap.Styles.StyleBrush fontBrush, Matrix2D transform)
        {
            System.Windows.Media.FormattedText fText = new System.Windows.Media.FormattedText(text, System.Threading.Thread.CurrentThread.CurrentCulture
                , System.Windows.FlowDirection.LeftToRight, SharpMap.Wpf.Rendering.ViewConverter.Convert(font), SharpMap.Wpf.Rendering.ViewConverter.ConvertPointsToFontSize(font.Size.Width), SharpMap.Wpf.Rendering.ViewConverter.Convert(fontBrush));

            System.Windows.Point origin = SharpMap.Wpf.Rendering.ViewConverter.Convert(layoutRectangle.UpperLeft);
            System.Windows.Media.Brush brush = SharpMap.Wpf.Rendering.ViewConverter.Convert(fontBrush);
            System.Windows.Media.Geometry geometry = fText.BuildGeometry(origin);
            System.Windows.Media.GeometryDrawing renderedObject = new System.Windows.Media.GeometryDrawing(brush, null, geometry);
            return renderedObject;
        }


        #region SelectRectangle

        private static void SelectRectangleQuery(ActionContext<IMapView2D, Point2D> context)
        {
            Point2D point = context.CurrentPoint;
            SharpMap.Geometries.Point worldPoint = context.MapView.ToWorld(point);
            context.MapView.IdentifyLocation(worldPoint);
            
        }

        /// <summary>
        /// Clear the view's current selection before starting a new one.
        /// </summary>
        /// <param name="context">
        /// An <see cref="ActionContext{IMapView2D, Point2D}"/> which provides 
        /// information about where, and on which view, the action occurred.
        /// </param>
        private static void SelectRectangleBegin(ActionContext<IMapView2D, Point2D> context)
        {
            //foreach (ILayer ilayer in context.Map.SelectedLayers)
            //{
            //    SharpMap.Styles.VectorStyle vStyle = ilayer.Style as SharpMap.Styles.VectorStyle;
            //    if (vStyle == null || !vStyle.AreFeaturesSelectable)
            //    {
            //        continue;
            //    }
            //    GeometryLayer gl = ilayer as GeometryLayer;
            //    gl.SelectedFeatures.ViewDefinition = new FeatureSpatialExpression(Point.Empty, SpatialExpressionType.Intersects, null);
            //}
            beginRuberBand(context);
        }

        /// <summary>
        /// Add the current point to the view's selection.
        /// </summary>
        /// <param name="context">
        /// An <see cref="ActionContext{IMapView2D, Point2D}"/> which provides 
        /// information about where, and on which view, the action occurred.
        /// </param>
        private static void SelectRectangleExtend(ActionContext<IMapView2D, Point2D> context)
        {
            continueRuberBand(context);
            //highlightFeatures(context);
        }

        /// <summary>
        /// Close the view's selection and set the map's GeometryFilter.
        /// </summary>
        /// <param name="context">
        /// An <see cref="ActionContext{IMapView2D, Point2D}"/> which provides 
        /// information about where, and on which view, the action occurred.
        /// </param>
        private static void SelectRectangleEnd(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;
            MapView viewControl = view as MapView;

            Rectangle2D selectionViewBounds = endRuberBand(context);

            // Create a BoundingBox for the view's selection using the map's world space
            BoundingBox selectionWorldBounds = new BoundingBox(
                view.ToWorld(selectionViewBounds.LowerLeft), view.ToWorld(selectionViewBounds.UpperRight));

          
            // Apply the GeometryFilter derived from the view's selection
            for (int i = context.Map.Layers.Count - 1; i >= 0; i--)
            {
                GeometryLayer layer = context.Map.Layers[i] as GeometryLayer;
                if (layer == null)
                {
                    continue;
                }

                SharpMap.Styles.VectorStyle vStyle = layer.Style as SharpMap.Styles.VectorStyle;
                if (vStyle == null || !vStyle.AreFeaturesSelectable)
                {
                    continue;
                }

                layer.HighlightedFeatures.ViewDefinition = 
                    new FeatureSpatialExpression(Point.Empty, 
                        layer.HighlightedFeatures.GeometryFilterType,EmptyOids);
                    //GeometryFilter = Point.Empty;


                if (layer.Enabled && layer.IsVisibleWhen(isInView(view.WorldWidth)))
                {
                    layer.SelectedFeatures.GeometryFilter = selectionWorldBounds.ToGeometry();
                }
            }
        }

        #endregion


        #region ZoomInRectangle
        private static void ZoomRectangleQuery(ActionContext<IMapView2D, Point2D> context)
        {
        }
         private static void ZoomRectangleBegin(ActionContext<IMapView2D, Point2D> context)
         {
             beginRuberBand(context);
         }
         private static void ZoomRectangleExtend(ActionContext<IMapView2D, Point2D> context)
         {
             continueRuberBand(context);
         }
        private static void ZoomRectangleEnd(ActionContext<IMapView2D, Point2D> context)
        {
            if (context.MapView.Selection.Path.Points.Count > 1)
            {
                Rectangle2D viewBounds = endRuberBand(context);
                context.MapView.ZoomToViewBounds(viewBounds);
            }
            else
            {
                zoomByFactor(context, 0.8);
            }
        } 
        #endregion
   
    

        #region Private Helper Methods
        // old way
        private static double MeasureDistance1(Point2D p1, Point2D p2)
        {
            double rad = 6378.137;
            double p1X = p1.X / 180.0 * Math.PI;
            double p1Y = p1.Y / 180.0 * Math.PI;
            double p2X = p2.X / 180.0 * Math.PI;
            double p2Y = p2.Y / 180.0 * Math.PI;

            return Math.Acos(Math.Sin(p1Y) * Math.Sin(p2Y) +
                                            Math.Cos(p1Y) * Math.Cos(p2Y) * Math.Cos(p2X - p1X)) * rad;
        }
        // new way
        private static double MeasureDistance2(Point2D p1, Point2D p2)
        {
        //    GeodeticCalculator geoCalc = new GeodeticCalculator();
        //    Ellipsoid reference = Ellipsoid.WGS84;
        //    GlobalCoordinates loc1 = new GlobalCoordinates(p1.X, p1.Y);
        //    GlobalCoordinates loc2 = new GlobalCoordinates(p2.X, p2.Y);

        //    GeodeticCurve geoCurve = geoCalc.CalculateGeodeticCurve(reference, loc1, loc2);

            //return geoCurve.EllipsoidalDistance / 1000.0;
            return 0.0;
        }

        //Correct way
        private static double MeasureDistance3(Map map, ILayer layer,  Point2D p1, Point2D p2)
        {
            CoordinateSystems.ICoordinateSystem coordSys = layer.CoordinateSystem;
            SharpMap.CoordinateSystems.Transformations.ICoordinateTransformation trans
                = layer.CoordinateTransformation;

            CoordinateSystems.ICoordinateSystem mapCoordSys = map.SpatialReference;
            
            
            CoordinateSystems.IUnit unit =coordSys.GetUnits(0);
            //CoordinateSystems.ProjectedCoordinateSystem projCoordSys = 
              //  new CoordinateSystems.ProjectedCoordinateSystem(
            CoordinateSystems.CoordinateSystemFactory fact = new SharpMap.CoordinateSystems.CoordinateSystemFactory();

            return 0.0;

        }
        
        private static void zoomByFactor(ActionContext<IMapView2D, Point2D> context, Double zoomFactor)
        {
            IMapView2D view = context.MapView;

            SharpMap.Geometries.Point oldCenter = view.GeoCenter;
            BoundingBox newEnvelope = new BoundingBox(
                                            new Point(view.ViewEnvelope.LowerLeft.X * zoomFactor,
                                                               view.ViewEnvelope.LowerLeft.Y * zoomFactor),
                                            new Point(view.ViewEnvelope.UpperRight.X * zoomFactor,
                                                               view.ViewEnvelope.UpperRight.Y * zoomFactor));
            //view.ZoomToWorldBounds(newEnvelope);
            System.Windows.UIElement uie = view as System.Windows.UIElement;
            if (uie != null)
            {
                MapCommands.ZoomToWorldBounds.Execute(newEnvelope, uie);
            }
            view.GeoCenter = oldCenter;
        }

        private static void beginRuberBand(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;

            if (view.GeoCenter == Point.Empty)
            {
                throw new InvalidOperationException("No visible region is set for this view.");
            }
          
            SharpMap.Styles.SolidStyleBrush brush = 
                new SharpMap.Styles.SolidStyleBrush(new SharpMap.Styles.StyleColor(200, 200, 0, 128));
            view.Selection.FillBrush = brush;
            view.Selection.OutlineStyle = new SharpMap.Styles.StylePen(SharpMap.Styles.StyleColor.Orange, 0.5);
            
            view.Selection.AnchorPoint = context.CurrentPoint;
            
        }

        private static void continueRuberBand(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;

            if (view.GeoCenter == Point.Empty)
            {
                throw new InvalidOperationException("No visible region is set for this view.");
            }
            
            Point2D anchor = view.Selection.AnchorPoint;
            view.Selection.Clear();

            Point2D topRight = new Point2D(context.CurrentPoint.X, anchor.Y);
            Point2D bottomRight = context.CurrentPoint;
            Point2D bottomLeft = new Point2D(anchor.X, context.CurrentPoint.Y);

            view.Selection.AddPoint(anchor);
            view.Selection.AddPoint(topRight);
            view.Selection.AddPoint(bottomRight);
            view.Selection.AddPoint(bottomLeft);
            view.Selection.Close();

        }
        private static Rectangle2D endRuberBand(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;
            Rectangle2D bounds = view.Selection.Path.Bounds;
            view.Selection.Clear();
            return bounds;
        }


        private static void highlightFeatures(ActionContext<IMapView2D, Point2D> context)
        {
            IMapView2D view = context.MapView;
            
            
            Rectangle2D viewBounds = view.Selection.Path.Bounds;

            // Create a BoundingBox for the view's selection using the map's world space
            BoundingBox worldBounds = new BoundingBox(
                view.ToWorld(viewBounds.LowerLeft), view.ToWorld(viewBounds.UpperRight));

            // Apply the GeometryFilter derived from the view's selection
            for (int i = context.Map.Layers.Count - 1; i >= 0; i--)
            {
                GeometryLayer layer = context.Map.Layers[i] as GeometryLayer;
                if (layer == null)
                {
                    continue;
                }

                SharpMap.Styles.VectorStyle vStyle = layer.Style as SharpMap.Styles.VectorStyle;
                if (vStyle == null || !vStyle.AreFeaturesSelectable)
                {
                    continue;
                }


                if (layer.Enabled && layer.IsVisibleWhen(isInView(view.WorldWidth)))
                {
                    layer.HighlightedFeatures.GeometryFilter = worldBounds.ToGeometry();
                }
            }
        }  

        private static Predicate<ILayer> isInView(Double scale)
        {
            return delegate(ILayer layer)
            {
                return layer.Style.MaxVisible >= scale &&
                       layer.Style.MinVisible <= scale;
            };
        }
        #endregion
    }




 
}
